home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / jwpsrc.zip / FILE.C < prev    next >
C/C++ Source or Header  |  1993-03-31  |  72KB  |  2,509 lines

  1. /* Copyright (C) Stephen Chung, 1991-1993.  All rights reserved. */
  2.  
  3. #include "jwp.h"
  4.  
  5. #include "idm.h"
  6. #include <math.h>
  7.  
  8.  
  9. /* Font Width tables */
  10.  
  11. static int SystemWT[256];
  12. static int AsciiWT[256];
  13. static int AsciiErrors[256];
  14.  
  15. #define FIRSTBLOCKSIZE  sizeof(PARAGRAPH)   /* So we can reuse the block */
  16. #define CARETWIDTH      2
  17.  
  18. #define DELAYCARET(x)   { delay = CaretDelayed; CaretDelayed = x; }
  19. #define RESTORECARET()  { CaretDelayed = delay; }
  20.  
  21. #define THERULER(x)     ((RULER(x).hwnd == NULL) ? 0 : RULERHEIGHT)
  22.  
  23.  
  24. extern BOOL FAR PASCAL KanjiInfoProc (HWND, WORD, WORD, LONG);
  25. extern BOOL FAR PASCAL JISInputProc (HWND, WORD, WORD, LONG);
  26. extern BOOL FAR PASCAL LookupProc (HWND, WORD, WORD, LONG);
  27. extern BOOL FAR PASCAL JISTableDlgProc (HWND, WORD, WORD, LONG);
  28.  
  29.  
  30. /* Mouse-related statics */
  31.  
  32. static BOOL CaretDelayed = FALSE;
  33. static BOOL capturing = FALSE;
  34. static BOOL MouseActivated = FALSE;
  35. static POINT LastSeen;
  36. static HWND PrevWindow = NULL;
  37.  
  38.  
  39.  
  40. void SwitchMenu (int menu)   /* 0 = full, 1 = minimal */
  41. {
  42.     static int curmenu = -1;
  43.     extern HMENU FullMenu, MinimalMenu;
  44.  
  45.     if (menu == curmenu) return;
  46.  
  47.     switch (menu) {
  48.         case 0: SetMenu(global.hwnd, FullMenu); hmenu = FullMenu; break;
  49.         case 1: SetMenu(global.hwnd, MinimalMenu); hmenu = MinimalMenu; break;
  50.         default: return;
  51.     }
  52.  
  53.     curmenu = menu;
  54.  
  55.     ProcessMenuTexts();
  56.     UpdateQuickFiles();
  57. }
  58.  
  59.  
  60.  
  61. void CloseFile (FILEOPTIONS *f)
  62. {
  63.     PARAGRAPH far *p, far *p2;
  64.     ONELINE far *lp1, far *lp2;
  65.  
  66.     TakeCareOfThings(f, TRUE);
  67.  
  68.     for (p = f->paragraph; p != NULL; ) {
  69.         for (lp1 = p->lines; lp1 != NULL; ) {
  70.             lp2 = lp1;
  71.             lp1 = lp1->next;
  72.             FreeStruct(lp2);
  73.         }
  74.         FreeBlock(p->text);
  75.  
  76.         p2 = p->next;
  77.         FreeStruct(p);
  78.         p = p2;
  79.     }
  80.  
  81.     FreeUndoChain(f->undo);
  82.     FreeUndoChain(f->redo);
  83. }
  84.  
  85.  
  86. BOOL Skip (POSITION *p, int n)
  87. {
  88.     if (n > 0) {
  89.         for(; n > 0; n--) {
  90.             if (p->line->next == NULL) {
  91.                 if (p->para->next == NULL) return (FALSE);
  92.                 p->para = p->para->next;
  93.                 p->line = p->para->lines;
  94.             } else {
  95.                 p->line = p->line->next;
  96.             }
  97.         }
  98.     } else {
  99.         for (; n < 0; n++) {
  100.             if (p->line->prev == NULL) {
  101.                 if (p->para->prev == NULL) return (FALSE);
  102.                 p->para = p->para->prev;
  103.                 p->line = p->para->lastline;
  104.             } else {
  105.                 p->line = p->line->prev;
  106.             }
  107.         }
  108.     }
  109.  
  110.     p->pos = 0;
  111.  
  112.     return (TRUE);
  113. }
  114.  
  115.  
  116.  
  117. void DoCaret (FILEOPTIONS *f, int x, int y, BOOL on)
  118. {
  119.     if (on) {
  120.         if (!CaretDelayed) {
  121.             if (!f->caret) {
  122.                 SetCaretPos((x > CARETWIDTH) ? x - CARETWIDTH / 2: x, y - LINEGAP(f)/2);
  123.                 ShowCaret(f->hwnd);
  124.                 f->caret = TRUE;
  125.             } else {
  126.                 SetCaretPos((x > CARETWIDTH) ? x - CARETWIDTH / 2: x, y - LINEGAP(f)/2);
  127.             }
  128.         }
  129.     } else {
  130.         if (f->caret) {
  131.             HideCaret(f->hwnd);
  132.             f->caret = FALSE;
  133.         }
  134.     }
  135. }
  136.  
  137.  
  138.  
  139. /* Width Table: 0 = System font, 1 = ASCII font, -1 = reload ASCII, -2 = reload all */
  140.  
  141. int FontCharWidth (int ch, int WidthTable)
  142. {
  143.     int i, width;
  144.     double ratio;
  145.     HDC hdc;
  146.     HFONT hfont;
  147.  
  148.     switch (WidthTable) {
  149.         case -2:
  150.             hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  151.             SelectObject(hdc, SYSTEM_FONT);
  152.             GetCharWidth(hdc, 0, 255, SystemWT);
  153.             DeleteDC(hdc);
  154.             /* falls into next case... */
  155.  
  156.         case -1:
  157.             hdc = GetPrinterDC(TRUE, NULL);
  158.             if (hdc == NULL) hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  159.             hfont = SelectAsciiFont(hdc, DefAsciiFont.facename, DefAsciiFont.size, NULL);
  160.             SelectObject(hdc, hfont);
  161.             if (!GetCharWidth(hdc, 0, 255, AsciiWT)) {
  162.                 ErrorMessage(global.hwnd, "WARNING: Cannot get font width table from the printer driver.  "
  163.                                           "Formatting may be messed up.");
  164.                 DeleteDC(hdc);
  165.                 DeleteObject(hfont);
  166.  
  167.                 hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  168.                 hfont = SelectAsciiFont(hdc, DefAsciiFont.facename, DefAsciiFont.size, NULL);
  169.                 SelectObject(hdc, hfont);
  170.                 GetCharWidth(hdc, 0, 255, AsciiWT);
  171.  
  172.                 DeleteDC(hdc);
  173.                 DeleteObject(hfont);
  174.             } else {
  175.                 DeleteDC(hdc);
  176.                 DeleteObject(hfont);
  177.             }
  178.  
  179.             ratio = (double) global.resolution.y / (double) global.resolution.x;
  180.             ratio *= global.dispscale / global.printscale;
  181.  
  182.             for (i = 0; i <= 255; i++) {
  183.                 width = AsciiWT[i] * 10;
  184.                 width = (int) floor((double) width * ratio + 0.5);
  185.                 AsciiWT[i] = width / 10;
  186.                 AsciiErrors[i] = width % 10;
  187.  
  188.                 if (AsciiErrors[i] > 0) {
  189.                     AsciiWT[i]++;
  190.                     AsciiErrors[i] = 10 - AsciiErrors[i];
  191.                 }
  192.             }
  193.  
  194.             return (0);
  195.  
  196.         case 0:
  197.             return (SystemWT[ch]);
  198.  
  199.         case 1:
  200.             return (AsciiWT[ch]);
  201.     }
  202.  
  203.     return (0);
  204. }
  205.  
  206.  
  207.  
  208. #ifdef FASTCOMPUTER
  209.  
  210. int FontDisplayError (int ch, PARAGRAPH far *pp, ONELINE far *lp)
  211. {
  212.     if (AsciiErrors[ch] == 0) return (0);
  213.     else if (AsciiErrors[ch] == 9) return (1);
  214.     else {
  215.         int i, n;
  216.  
  217.         for (i = n = 0; i < lp->length; i++) if (pp->text[lp->position + i].kanji == ch) n++;
  218.  
  219.         if (AsciiErrors[ch] > 0 && n % (10 - AsciiErrors[ch]) == 0) return (1);
  220.  
  221.         return (0);
  222.     }
  223. }
  224.  
  225. #else
  226.  
  227. int FontDisplayError (int ch, int pos)
  228. {
  229.     if (AsciiErrors[ch] > 0 && pos % (10 - AsciiErrors[ch]) == 0) return (1);
  230.     return (0);
  231. }
  232.  
  233. #endif FASTCOMPUTER
  234.  
  235.  
  236. DWORD GetDimension (FILEOPTIONS *f, POSITION p, int x)
  237. {
  238.     DWORD dimension;
  239.     BYTE ch;
  240.  
  241.     if (KANJIPOS(p)) {
  242.         dimension = MAKELONG(f->basefont->width, f->basefont->height);
  243.         return (dimension);
  244.     }
  245.  
  246.     ch = CHAROF(p, POSOF(p));
  247.  
  248.     if (!ch) {
  249.         dimension = MAKELONG(0, f->basefont->height);
  250.         return (dimension);
  251.     } else if (ch == '\t') {
  252.         if (x < 0) {
  253.             dimension = (-x) % BASEWIDTH(f);
  254.             if (dimension == 0) dimension = BASEWIDTH(f);
  255.         } else {
  256.             dimension = BASEWIDTH(f) - (x % BASEWIDTH(f));
  257.         }
  258.         dimension = MAKELONG(dimension, f->basefont->height);
  259.     } else {
  260.         if (ch < ' ') ch = (global.draftview ? global.textmetric.tmDefaultChar : DefAsciiFont.textmetric.tmDefaultChar);
  261.  
  262.         if (global.draftview || !(f->type & FN_NORMAL)) {
  263.             dimension = MAKELONG(FontCharWidth(ch, 0), AVGHEIGHT);
  264.         } else {
  265.             int width;
  266.  
  267.             //width = FontCharWidth(ch,1) - FontDisplayError(ch, PARAOF(p), LINEOF(p));
  268.             width = FontCharWidth(ch,1) - FontDisplayError(ch, POSOF(p));
  269.  
  270.             dimension = MAKELONG(width, DefAsciiFont.textmetric.tmHeight);
  271.         }
  272.     }
  273.  
  274.     return (dimension);
  275. }
  276.  
  277.  
  278.  
  279. void FillCPos (FILEOPTIONS *f, PARAGRAPH far *para, int from, int to)
  280. {
  281.     int i, j, k, abspos, len;
  282.     int limit = C64K / sizeof(POINT);
  283.     unsigned int cpossize;
  284.     POSITION p;
  285.     UNIT far *cp;
  286.  
  287.  
  288.     /* Check the size of array */
  289.  
  290.     len = unitlen(para->text);
  291.  
  292.     cpossize = (len * sizeof(POINT)) / CPOSPAGESIZE;
  293.     cpossize = (cpossize + 1) * CPOSPAGESIZE;
  294.  
  295.     if (cpossize > C64K) {
  296.         ErrorMessage(global.hwnd, "Warning!  Too many characters in the paragraph!!!");
  297.         return;
  298.     }
  299.  
  300.     if (global.cpossize != cpossize) {
  301.         global.cpos = (POINT far *) BlockRealloc(global.cpos, cpossize);
  302.         global.cpossize = cpossize;
  303.     }
  304.  
  305.  
  306.     for (i = from, cp = para->text + from; ; cp++, i++) {
  307.         if (i >= limit) {
  308.             ErrorMessage(global.hwnd, "Too many characters in a paragraph!");
  309.             break;
  310.         }
  311.         if (to >= 0 && i > to) break;
  312.  
  313.         global.cpos[i].x = -1;
  314.         global.cpos[i].y = -1;
  315.  
  316.         if (!cp->kanji) break;
  317.     }
  318.  
  319.     global.cposcount = i + 1;
  320.  
  321.     p = f->top;
  322.     j = LINEGAP(f);
  323.  
  324.     do {
  325.         j += LINEOF(p)->height;
  326.         if (j > f->height) break;
  327.         if (PARAOF(p) != para) {
  328.             j += PARAOF(p)->spacing;
  329.             continue;
  330.         }
  331.         i = LEFTMARGIN(p) * BASEWIDTH(f) - f->startx;
  332.  
  333.         for (k = 0; k <= LINEOF(p)->length; k++) {
  334.             POSOF(p) = k;
  335.             abspos = POS2ABS(p);
  336.             if (abspos < from || (to >= 0 && abspos > to)) continue;
  337.  
  338.             global.cpos[abspos].x = i;
  339.             global.cpos[abspos].y = j;
  340.             if (k < LINEOF(p)->length) {
  341.                 i += LOWORD(GetDimension(f, p, i));
  342.  
  343.                 if (CHAROF(p, POSOF(p)) == '\n') {
  344.                     /* Nothing */
  345.                 } else if (CHAROF(p, POSOF(p)) != '\t') {
  346.                     if (KANJIPOS(p) || (POSOF(p) < LINEOF(p)->length - 1 && KANJIAT(p,POSOF(p)+1)))
  347.                         i += f->leading;
  348.                 }
  349.             }
  350.         }
  351.  
  352.         j += PARAOF(p)->spacing;
  353.     } while (NEXTLINE(p));
  354.  
  355.     global.cpospara = para;
  356. }
  357.  
  358.  
  359.  
  360. static void ShiftCPos(FILEOPTIONS *f, int dx, int dy)
  361. {
  362.     int i;
  363.  
  364.     for (i = 0; i < global.cposcount; i++) {
  365.         if (global.cpos[i].x >= 0) global.cpos[i].x += dx;
  366.         if (global.cpos[i].y >= 0) global.cpos[i].y += dy;
  367.  
  368.         if (global.cpos[i].y < 0 || global.cpos[i].y > f->height)
  369.             global.cpos[i].y = -1;
  370.     }
  371. }
  372.  
  373.  
  374.  
  375. int CalcLength (FILEOPTIONS *f, POSITION *pos)
  376. {
  377.     int i;
  378.     POSITION p = *pos;
  379.  
  380.     for (i = POSOF(p) = 0; POSOF(p) < POSOF(*pos); POSOF(p)++) {
  381.         i += LOWORD(GetDimension(f, p, i));
  382.  
  383.         if (CHAROF(p, POSOF(p)) == '\n') {
  384.             /* Nothing */
  385.         } else if (CHAROF(p, POSOF(p)) != '\t') {
  386.             if (KANJIPOS(p) || (POSOF(p) < LINEOF(p)->length - 1 && KANJIAT(p,POSOF(p)+1)))
  387.                 i += f->leading;
  388.         }
  389.     }
  390.  
  391.     return (i + BASEWIDTH(f) * LEFTMARGIN(p));
  392. }
  393.  
  394.  
  395.  
  396. static BOOL MatchPseudo(FILEOPTIONS *f, BOOL horizontal, BOOL CanHaveNoMatch)
  397. {
  398.     int i, j, k, w;
  399.     POSITION p = f->current;
  400.  
  401.     if (horizontal) {
  402.         for(POSOF(p) = 0, i = BASEWIDTH(f) * LEFTMARGIN(p) - f->startx;
  403.             POSOF(p) < CURLINE(f)->length && i <= PSEUDOX(f); POSOF(p)++) {
  404.                 i += LOWORD(GetDimension(f, p, i));
  405.  
  406.                 if (CHAROF(p, POSOF(p)) != '\t') {
  407.                     if (KANJIPOS(p) || (POSOF(p) < LINEOF(p)->length - 1 && KANJIAT(p,POSOF(p)+1)))
  408.                         i += f->leading;
  409.                 }
  410.         }
  411.  
  412.         if (POSOF(p) > 0 && (POSOF(p) < LINEOF(p)->length || i > PSEUDOX(f))) {
  413.             POSOF(p)--;
  414.             w = LOWORD(GetDimension(f, p, i));     /* Char width */
  415.             if (CHAROF(p, POSOF(p)) != '\t') {
  416.                 if (KANJIPOS(p) || (POSOF(p) < LINEOF(p)->length - 1 && KANJIAT(p,POSOF(p)+1)))
  417.                     w += f->leading;
  418.             }
  419.  
  420.             if (i >= PSEUDOX(f) + (w / 2)) {
  421.                 i -= w;
  422.             } else {
  423.                 POSOF(p)++;
  424.             }
  425.         }
  426.  
  427.         if (i < 0 || i >= f->width) {
  428.             i += f->startx;
  429.             if (i >= f->width) {
  430.                 /* Move it to the middle */
  431.                 k = (i - (f->width / 3)) / BASEWIDTH(f);
  432.                 f->startx = k * BASEWIDTH(f);
  433.                 CURX(f) = i - f->startx;
  434.             } else {
  435.                 f->startx = 0;
  436.                 CURX(f) = i;
  437.             }
  438.             SetHorzScroll(f);
  439.             CURCHAR(f) = POSOF(p);
  440.             FillCPos(f, CURPARA(f), 0, -1);
  441.             InvalidateRect(f->hwnd, NULL, TRUE);
  442.             UpdateWindow(f->hwnd);
  443.             return (TRUE);
  444.         }
  445.  
  446.         CURX(f) = i;
  447.         CURCHAR(f) = POSOF(p);
  448.         return (TRUE);
  449.     } else {
  450.         p = f->top;
  451.         j = LINEGAP(f);          /* Vertical height */
  452.  
  453.         for (;;) {
  454.             j += LINEOF(p)->height;
  455.             if (j >= PSEUDOY(f)) break;
  456.             if (!NEXTLINE(p)) break;
  457.             j += PARAOF(p)->spacing;
  458.         }
  459.  
  460.         if (j >= PSEUDOY(f) || !CanHaveNoMatch) {
  461.             f->current = p;
  462.             CURY(f) = j;
  463.             return (TRUE);
  464.         } else {
  465.             return (FALSE);
  466.         }
  467.     }
  468. }
  469.  
  470.  
  471.  
  472. BOOL FindCaret (FILEOPTIONS *f, BOOL LongMethod)
  473. {
  474.     int i, j, k;
  475.     POSITION p;
  476.  
  477.     if (!LongMethod) {
  478.         if (global.cpospara != CURPARA(f)) FillCPos(f, CURPARA(f), 0, -1);
  479.  
  480.         i = POS2ABS(f->current);
  481.  
  482.         if (CURCHAR(f) >= CURLINE(f)->length) {
  483.             CURX(f) = CURLINE(f)->width - f->startx;
  484.             if (CURX(f) < 0 || CURX(f) >= f->width) CURX(f) = -1;
  485.             if (CURLINE(f)->length > 0) i--;
  486.             CURY(f) = global.cpos[i].y;
  487.         } else {
  488.             CURX(f) = global.cpos[i].x;
  489.             CURY(f) = global.cpos[i].y;
  490.         }
  491.         return (CURX(f) >= 0 && CURY(f) >= 0 &&
  492.                 CURX(f) < f->width && CURY(f) < f->height);
  493.     } else {
  494.         p = f->top;
  495.         j = LINEGAP(f);         /* Vertical position */
  496.  
  497.         do {
  498.             j += LINEOF(p)->height;
  499.  
  500.             if (j > f->height) return (FALSE);
  501.  
  502.             if (LINEOF(p) == CURLINE(f)) {
  503.                 k = CalcLength(f, &(f->current)) - f->startx;
  504.                 if (k < 0 || k >= f->width) break;
  505.  
  506.                 CURX(f) = k;
  507.                 CURY(f) = j;
  508.                 return (TRUE);
  509.             }
  510.  
  511.             j += PARAOF(p)->spacing;
  512.         } while (NEXTLINE(p));
  513.  
  514.         return (FALSE);
  515.     }
  516. }
  517.  
  518.  
  519.  
  520. void FindScrollPos(FILEOPTIONS *f)
  521. {
  522.     POSITION p;
  523.  
  524.     if (f->type & FN_NOSCROLLBARS) return;
  525.  
  526.     PARAOF(p) = f->paragraph;
  527.     LINEOF(p) = PARAOF(p)->lines;
  528.  
  529.     f->vscroll = 0;
  530.  
  531.     do {
  532.         if (PARAOF(p) == CURPARA(f) && LINEOF(p) == CURLINE(f)) break;
  533.         (f->vscroll)++;
  534.     } while (NEXTLINE(p));
  535. }
  536.  
  537.  
  538.  
  539. void SetHorzScroll(FILEOPTIONS *f)
  540. {
  541.     if (f->startx < 0) f->startx = 0;
  542.  
  543.     if (!(f->type & FN_NORMAL) || (f->type & FN_NOSCROLLBARS)) return;
  544.  
  545.     if (f->startx < (f->linelen * BASEWIDTH(f))) {
  546.         SetScrollPos(f->parent, SB_HORZ, f->startx / BASEWIDTH(f), TRUE);
  547.     } else {
  548.         SetScrollPos(f->parent, SB_HORZ, f->linelen, TRUE);
  549.     }
  550. }
  551.  
  552.  
  553.  
  554. void MoveIntoWindow (FILEOPTIONS *f)
  555. {
  556.     BOOL inside;
  557.     POSITION p;
  558.     int i, j;
  559.  
  560.     /* Line within window? */
  561.  
  562.     p = f->top;
  563.     j = LINEGAP(f);
  564.     inside = FALSE;
  565.  
  566.     do {
  567.         j += LINEOF(p)->height;
  568.         if (j + LINEGAP(f) > f->height) {
  569.             break;
  570.         } else if (LINEOF(p) == CURLINE(f)) {
  571.             inside = TRUE;
  572.             break;
  573.         }
  574.         j += PARAOF(p)->spacing;
  575.     } while (NEXTLINE(p));
  576.  
  577.     if (!inside) {
  578.  
  579.         /* Move it half-way into the window */
  580.  
  581.         p = f->current;
  582.         j = LINEGAP(f);
  583.  
  584.         do {
  585.             j += LINEOF(p)->height;
  586.             if (j + LINEGAP(f) > f->height / 2) break;
  587.             j += PARAOF(p)->spacing;
  588.         } while (PREVLINE(p));
  589.  
  590.         f->top = p;
  591.  
  592.         if ((f->type & FN_NORMAL) && !(f->type & FN_NOSCROLLBARS)) {
  593.             FindScrollPos(f);
  594.             SetScrollPos(f->parent, SB_VERT, f->vscroll, TRUE);
  595.         }
  596.     }
  597.  
  598.     i = CalcLength (f, &(f->current)) - f->startx;
  599.     if (i >= 0 && i < f->width) return;
  600.  
  601.     i += f->startx;         /* Total length */
  602.  
  603.     if (i < f->width) {
  604.         f->startx = 0;
  605.     } else {
  606.         /* Move it to the middle */
  607.  
  608.         j = (i - (f->width / 3)) / BASEWIDTH(f);
  609.         f->startx = j * BASEWIDTH(f);
  610.     }
  611.  
  612.     SetHorzScroll(f);
  613.  
  614.     FillCPos(f, CURPARA(f), 0, -1);
  615. }
  616.  
  617.  
  618.  
  619. void TakeCareOfThings (FILEOPTIONS *f, BOOL IncludingConversion)
  620. {
  621.     if (SELTYPE(f) == SEL_SELECTION || IncludingConversion) {
  622.         if (SELPARA1(f) != NULL) TurnOffSelection(f);
  623.         SELPARA1(f) = SELPARA2(f) = NULL;
  624.         SELPOS1(f) = SELPOS2(f) = 0;
  625.     }
  626.  
  627.     if (IncludingConversion) {
  628.         SELNOW(f) = FALSE;
  629.         CharInput(f, '\0');
  630.     }
  631. }
  632.  
  633.  
  634.  
  635. /* 0 = white space, 1 = letter, 2 = kana, 3 = kanji */
  636.  
  637. static int GetCharType (KANJI ch)
  638. {
  639.     if (ISASCII(ch)) {
  640.         if (ch <= ' ') return (0);
  641.         else return (1);
  642.     } else if (HIBYTE(ch) < 0x24) {
  643.         return (0);
  644.     } else {
  645.         if (HIBYTE(ch) == 0x24 || HIBYTE(ch) == 0x25) return (2);
  646.         else return (3);
  647.     }
  648. }
  649.  
  650.  
  651.  
  652. /* 0 = space, 1 = kanji symbol, 2 = ASCII, 3 = kanji */
  653.  
  654. static int CategorizeChar (KANJI ch)
  655. {
  656.     if (!ch || ch == ' ' || ch == 0x2121) return (0);
  657.     else if (ISASCII(ch)) return (2);
  658.     else if (HIBYTE(ch) < 0x30) return (1);
  659.     else return (3);
  660. }
  661.  
  662.  
  663.  
  664. void ToggleInputMode (void)
  665. {
  666.     int i;
  667.  
  668.     i = SendMessage(global.tbhwnd, BM_GETSTATE, 0, ID_KANA);
  669.     SendMessage(global.tbhwnd, BM_SETSTATE, !i, ID_KANA);
  670.     SendMessage(global.tbhwnd, BM_SETSTATE, i, ID_ASCII);
  671.     //EnableToolbarButton(global.tbhwnd, ID_BOLD, i);
  672.     //EnableToolbarButton(global.tbhwnd, ID_ITALICS, i);
  673.     //EnableToolbarButton(global.tbhwnd, ID_REVERSE, !i);
  674.  
  675.     if (global.mode == M_KANA) {
  676.         global.mode = M_ASCII;
  677.         StatusMessage("Switched to Text mode");
  678.     } else {
  679.         global.mode = M_KANA;
  680.         StatusMessage("Switched to Hiragana mode");
  681.     }
  682. }
  683.  
  684.  
  685.  
  686. static ASCIIFONT *LoadASCIIFont (HDC hdc, FILEOPTIONS *f)
  687. {
  688.     ASCIIFONT *CurFont;
  689.  
  690.     CurFont = &DefAsciiFont;
  691.     if ((f->type & FN_NORMAL) && !global.draftview) {
  692.         SelectObject(hdc, CurFont->hfont);
  693.     } else {
  694.         SelectObject(hdc, SYSTEM_FONT);
  695.     }
  696.     SetMapperFlags(hdc, TRUE);
  697.  
  698.     return (CurFont);
  699. }
  700.  
  701.  
  702.  
  703. void RedrawFile (FILEOPTIONS *f, HDC hdc, int OffsetX, int OffsetY, RECT far *rp, BOOL ShowSpecial)
  704. {
  705.     int i, j, k, l, r, RealWidth;
  706.     int lgap, cgap;
  707.     char ch;
  708.     KANJI c1, c2, c3;
  709.     BOOL insel;
  710.     HDC fhdc;
  711.     DWORD dimension;
  712.     BYTE far *cbufp;
  713.     ASCIIFONT *CurFont;
  714.     POSITION p;
  715.     RECT rect;
  716.  
  717.  
  718.     SetBkMode(hdc, TRANSPARENT);
  719.  
  720.     if (rp == NULL) {
  721.         rp = ▭
  722.         GetClientRect(f->hwnd, &rect);
  723.     }
  724.  
  725.     if (OffsetX != 0 || OffsetY != 0) SetWindowOrg(hdc, OffsetX, OffsetY);
  726.  
  727.  
  728.     /* Does it start in a selection? */
  729.  
  730.     insel = FALSE;
  731.  
  732.     if (SELPARA1(f) != NULL) insel = InSelection(f, f->top);
  733.  
  734.  
  735.     lgap = LINEGAP(f);  if (lgap <= 0) lgap = 1;
  736.     CurFont = NULL;
  737.  
  738.  
  739.     fhdc = f->hdc;
  740.     f->hdc = hdc;
  741.  
  742.     p = f->top;
  743.     j = LINEGAP(f);         /* Vertical position */
  744.  
  745.     do {
  746.         j += LINEOF(p)->height;
  747.  
  748.         if (j - LINEOF(p)->height - lgap > rp->bottom) break;
  749.  
  750.         if (j + lgap < rp->top) {
  751.             if (PARAOF(p) == SELPARA1(f) && LINEOF(p)->position <= SELPOS1(f) &&
  752.                 (LINEOF(p)->position + LINEOF(p)->length) > SELPOS1(f))
  753.                     insel = TRUE;
  754.             if (PARAOF(p) == SELPARA2(f)) {
  755.                 if (LINEOF(p)->next == NULL) {
  756.                     if (LINEOF(p)->position + LINEOF(p)->length >= SELPOS2(f))
  757.                         insel = FALSE;
  758.                 } else {
  759.                     if (LINEOF(p)->position + LINEOF(p)->length > SELPOS2(f))
  760.                         insel = FALSE;
  761.                 }
  762.             }
  763.  
  764.             j += PARAOF(p)->spacing;
  765.             continue;
  766.         }
  767.  
  768.         /* Horizontal position */
  769.  
  770.         i = BASEWIDTH(f) * LEFTMARGIN(p) - f->startx;
  771.  
  772.         for (k = 0; k <= LINEOF(p)->length; k++) {
  773.             POSOF(p) = k;
  774.             cgap = CHARGAP(f);
  775.  
  776.             c1 = (k <= 0) ? 0 : CHAROF(p,k-1);
  777.             c2 = CHAROF(p,k);
  778.             c3 = (k < LINEOF(p)->length - 1) ? CHAROF(p,k+1) : 0;
  779.  
  780.             if (LINEOF(p)->next != NULL && k >= LINEOF(p)->length) {
  781.                 if (CurFont == NULL) CurFont = LoadASCIIFont(hdc, f);
  782.  
  783.                 if (ShowSpecial && (f->type & FN_NORMAL) && c2 == '\n') {
  784.                         ch = 0xab;     /* << symbol */
  785.                         TextOut(hdc, i, j - (global.draftview ? AVGHEIGHT : DefAsciiFont.textmetric.tmHeight), &ch, 1);
  786.                 }
  787.                 break;
  788.             }
  789.  
  790.  
  791.             if (SELPARA1(f) == NULL) {
  792.                 insel = FALSE;
  793.             } else if (!insel && PARAOF(p) == SELPARA1(f) && &UNITOF(p,k) == &SELCHAR1(f)) {
  794.                 insel = TRUE;
  795.  
  796.                 if ((k <= 0 && LINEOF(p)->length > 0) || (ISKANJI(c2) && c1 != '\t') || ISKANJI(c1)) {
  797.                     PatBlt(hdc, i - CHARGAP(f), j - LINEOF(p)->height - lgap,
  798.                             CHARGAP(f), LINEOF(p)->height + 2 * lgap, DSTINVERT);
  799.                 }
  800.             } else if (insel && PARAOF(p) == SELPARA2(f) && &UNITOF(p,k) > &SELCHAR2(f)) {
  801.                 insel = FALSE;
  802.             } else if (insel && k == 0 && LINEOF(p)->length > 0) {
  803.                 PatBlt(hdc, i - CHARGAP(f), j - LINEOF(p)->height - lgap,
  804.                         CHARGAP(f), LINEOF(p)->height + 2 * lgap, DSTINVERT);
  805.             } else if (insel && k > 0 && k < LINEOF(p)->length) {
  806.                 if ((ISKANJI(c2) && c1 != '\t') || ISKANJI(c1)) {
  807.                     PatBlt(hdc, i - f->leading + CHARGAP(f), j - LINEOF(p)->height - lgap,
  808.                             f->leading - CHARGAP(f), LINEOF(p)->height + 2 * lgap, DSTINVERT);
  809.                 }
  810.             }
  811.  
  812.             if (k >= LINEOF(p)->length) {
  813.                 if (insel && PARAOF(p) == SELPARA2(f) && &UNITOF(p,k) >= &SELCHAR2(f))
  814.                     insel = FALSE;
  815.  
  816.                 if (PARAOF(p) == global.cpospara && LINEOF(p)->next == NULL) {
  817.                     global.cpos[POS2ABS(p)].x = i;
  818.                     global.cpos[POS2ABS(p)].y = j;
  819.                 }
  820.  
  821.                 if (CurFont == NULL) CurFont = LoadASCIIFont(hdc, f);
  822.  
  823.                 if (ShowSpecial && (f->type & FN_NORMAL)) {
  824.                     ch = 0xb6;     /* Paragraph symbol */
  825.                     TextOut(hdc, i, j - (global.draftview ? AVGHEIGHT : DefAsciiFont.textmetric.tmHeight), &ch, 1);
  826.                 }
  827.                 break;
  828.             }
  829.  
  830.             if (j + lgap <= rp->top) continue;
  831.  
  832.             if (!ISKANJI(c2)) cgap = 0;
  833.  
  834.             dimension = GetDimension(f, p, i);
  835.  
  836.             l = RealWidth = LOWORD(dimension);  /* Char width */
  837.  
  838.             if (c2 != '\t') {
  839.                 if (ISKANJI(c2) || ISKANJI(c3)) l += f->leading;
  840.             }
  841.  
  842.             if (i + RealWidth + cgap <= rp->left || i - cgap >= rp->right) {
  843.                 i += l;
  844.                 continue;
  845.             }
  846.  
  847.             if (PARAOF(p) == global.cpospara) {
  848.                 global.cpos[POS2ABS(p)].x = i;
  849.                 global.cpos[POS2ABS(p)].y = j;
  850.             }
  851.  
  852.             if (ISKANJI(c2)) {
  853.                 r = Jis2Index(c2, f->basefont->holes);
  854.                 if (r < 0) r = Jis2Index(BADKANJI, f->basefont->holes);
  855.                 r = GetKanjiBitmap(f->basefont, r, &cbufp);
  856.                 DisplayKanjiBitmap(hdc, i, j, f->basefont->width, f->basefont->height,
  857.                                     r, SRCCOPY, cbufp);
  858.             } else {
  859.                 if (CurFont == NULL) CurFont = LoadASCIIFont(hdc, f);
  860.  
  861.                 switch (c2) {
  862.                     case ' ':
  863.                         ch = 0xb7;     /* Space symbol */
  864.                         if (ShowSpecial && (f->type & FN_NORMAL)) {
  865.                             TextOut(hdc, i, j - (global.draftview ? AVGHEIGHT : DefAsciiFont.textmetric.tmHeight), &ch, 1);
  866.                         }
  867.                         break;
  868.  
  869.                     case '\t':
  870.                         ch = 0xbb;     /* >> symbol */
  871.                         if (ShowSpecial && (f->type & FN_NORMAL)) {
  872.                             int x, height;
  873.  
  874.                             height = global.draftview ? AVGHEIGHT : DefAsciiFont.textmetric.tmHeight;
  875.                             x = j - height;
  876.  
  877.                             if (height < f->basefont->height) {
  878.                                 x -= (f->basefont->height - height) / 2;
  879.                             }
  880.                             TextOut(hdc, i, x, &ch, 1);
  881.                         }
  882.                         break;
  883.  
  884.                     case '\n':
  885.                         ch = 0xab;     /* << symbol */
  886.                         if (ShowSpecial && (f->type & FN_NORMAL)) {
  887.                             TextOut(hdc, i, j - (global.draftview ? AVGHEIGHT : DefAsciiFont.textmetric.tmHeight), &ch, 1);
  888.                         }
  889.                         break;
  890.  
  891.                     case '\r': break;   /* Shouldn't happen */
  892.  
  893.                     default:
  894.                         if (c2 < ' ') ch = DefAsciiFont.textmetric.tmDefaultChar;
  895.                         else ch = c2;
  896.  
  897.                         TextOut(hdc, i, j - HIWORD(dimension), &ch, 1);
  898.                         break;
  899.                 }
  900.             }
  901.  
  902.             if (insel) {
  903.                 PatBlt(hdc, i, j - LINEOF(p)->height - lgap,
  904.                         RealWidth + ((RealWidth < l) ? CHARGAP(f) : 0),
  905.                         LINEOF(p)->height + 2 * lgap, DSTINVERT);
  906.             }
  907.  
  908.             i += l;
  909.  
  910.         }
  911.  
  912.         j += PARAOF(p)->spacing;
  913.     } while (NEXTLINE(p));
  914.  
  915.     f->hdc = fhdc;
  916. }
  917.  
  918.  
  919. LONG FAR PASCAL FileWinProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  920. {
  921.     int         i, j, r;
  922.     int         shift, ctrl;
  923.     int         OldCharType, NewCharType;
  924.     HDC            hdc;
  925.     PAINTSTRUCT    ps;
  926.     POSITION    p;
  927.     POINT       point;
  928.     FILEOPTIONS *f;
  929.     BOOL        scrolled, delay;
  930.     RECT        cliprect;
  931.  
  932.  
  933.     /* Look for the current file */
  934.  
  935.     f = (FILEOPTIONS *) GetWindowWord(hwnd, 0);
  936.  
  937.  
  938.     switch (message) {
  939.  
  940.     case WM_CREATE:
  941.         SetWindowWord(hwnd, 0, (WORD) curfile);
  942.         return (0);
  943.  
  944.     case WM_SIZE:
  945.         f->width = LOWORD(lParam);
  946.         f->height = HIWORD(lParam);
  947.         return (0);
  948.  
  949.     case WM_COMMAND:
  950.         if (capturing) return (0);
  951.         switch (wParam) {
  952.             case IDM_EDITUNDO:
  953.                 UndoOneStep(f);
  954.                 return (0);
  955.  
  956.             case IDM_EDITREDO:
  957.                 RedoOneStep(f);
  958.                 return (0);
  959.  
  960.             case IDM_EDITCUT:
  961.                 shift = TRUE;   ctrl = FALSE;   wParam = VK_DELETE;
  962.                 goto KeyDown;
  963.  
  964.             case IDM_EDITCOPY:
  965.                 shift = FALSE;  ctrl = TRUE;    wParam = VK_INSERT;
  966.                 goto KeyDown;
  967.  
  968.             case IDM_EDITPASTE:
  969.                 shift = TRUE;   ctrl = FALSE;   wParam = VK_INSERT;
  970.                 goto KeyDown;
  971.  
  972.             case IDM_EDITCLEAR:
  973.                 shift = FALSE;  ctrl = FALSE;   wParam = VK_DELETE;
  974.                 goto KeyDown;
  975.  
  976.             case IDM_EDITSELECTALL: {
  977.                 TakeCareOfThings(f, TRUE);
  978.  
  979.                 SELPARA1(f) = f->paragraph;
  980.                 SELPOS1(f) = 0;
  981.                 SELPARA2(f) = f->eof;
  982.                 SELPOS2(f) = unitlen(f->eof->text);
  983.                 if (SELPOS2(f) > 0) SELPOS2(f)--;
  984.                 SELTYPE(f) = SEL_SELECTION;
  985.                 SELNOW(f) = FALSE;
  986.  
  987.                 CURPARA(f) = f->eof;
  988.                 CURLINE(f) = CURPARA(f)->lastline;
  989.                 CURCHAR(f) = CURLINE(f)->length;
  990.  
  991.                 if (!FindCaret(f, TRUE)) {
  992.                     MoveIntoWindow(f);
  993.                     InvalidateRect(hwnd, NULL, TRUE);
  994.                     UpdateWindow(hwnd);
  995.                 } else {
  996.                     FlipHighlight(f);
  997.                 }
  998.                 f->pseudo = f->cursor;
  999.                 DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  1000.                 Triangles(f);
  1001.                 return (0);
  1002.             }
  1003.  
  1004.             case IDM_KANJICONVERT:
  1005.             case IDM_KANJILCONVERT:
  1006.                 if (!ConvertOK(f)) {
  1007.                     MessageBeep(0);
  1008.                     return (0);
  1009.                 }
  1010.  
  1011.                 CharInput(f, '\x07');
  1012.  
  1013.                 if (SELNOW(f) || SELTYPE(f) == SEL_SELECTION) {
  1014.                     ConvertNow(f, FALSE);
  1015.                 } else {
  1016.                     SendMessage(global.convhwnd, WM_KEYDOWN,
  1017.                                 (wParam == IDM_KANJILCONVERT) ? VK_LEFT : VK_RIGHT, 0L);
  1018.                     SendMessage(global.convhwnd, WM_KEYDOWN, VK_RETURN, 0L);
  1019.                 }
  1020.                 return (0);
  1021.  
  1022.             case IDM_TOGGLEMODE:
  1023.                 if (f->type & FN_NOSWITCHING) {
  1024.                     MessageBeep(0);
  1025.                     return (0);
  1026.                 } else if (f->type & FN_EITHER) {
  1027.                     if (f->nr_bytes > 0) {
  1028.                         MessageBeep(0);
  1029.                         return (0);
  1030.                     }
  1031.                 }
  1032.  
  1033.                 TakeCareOfThings (f, TRUE);
  1034.                 ToggleInputMode();
  1035.  
  1036.                 if (!(f->type & FN_NORMAL)) {
  1037.                     HWND hwnd1;
  1038.  
  1039.                     hwnd1 = GetWindowWord(hwnd, sizeof(FILEOPTIONS *) + 2 * sizeof(WORD));
  1040.                     if (hwnd1 != NULL) InvalidateRect(hwnd1, NULL, FALSE);
  1041.                 }
  1042.  
  1043.                 return (0);
  1044.  
  1045.             case IDM_KANJIINFO: {
  1046.                 KANJI ch = 0;
  1047.  
  1048.                 if (SELPARA1(f) != NULL && SELPARA2(f) != NULL && (SELPARA1(f) == SELPARA2(f))) {
  1049.                     for (i = SELPOS1(f); i <= SELPOS2(f); i++) {
  1050.                         ch = SELPARA1(f)->text[i].kanji & 0x7f7f;
  1051.                         if (ch >= 0x3021) break;
  1052.                     }
  1053.                 }
  1054.  
  1055.                 if (!ch || ch < 0x3021) {
  1056.                     ErrorMessage(global.hwnd, "You must select a KANJI or KANA.");
  1057.                     return (0);
  1058.                 }
  1059.  
  1060.                 SetKanjiInfoChar (ch);
  1061.  
  1062.                 curfile = f;
  1063.                 DialogBox (hInstance, "KanjiInfo", f->parent, KanjiInfoProc);
  1064.                 return (0);
  1065.             }
  1066.  
  1067.             case IDM_KANJIINPUT:
  1068.                 curfile = f;
  1069.                 DialogBox (hInstance, "KanjiInput", f->parent, JISInputProc);
  1070.                 return (0);
  1071.  
  1072.             case IDM_KANJILOOKUP:
  1073.                 curfile = f;
  1074.                 DialogBox (hInstance, "KanjiLookup", f->parent, LookupProc);
  1075.                 return (0);
  1076.  
  1077.             case IDM_KANJITABLE:
  1078.                 curfile = f;
  1079.                 DialogBox (hInstance, "JISTable", f->parent, JISTableDlgProc);
  1080.                 return (0);
  1081.         }
  1082.         return (0);
  1083.  
  1084.     WM_CHAR_Case:
  1085.     case WM_CHAR:
  1086.         if (capturing) return (0);
  1087.  
  1088.         shift = (GetKeyState(VK_SHIFT) < 0);
  1089.         ctrl = (GetKeyState(VK_CONTROL) < 0);
  1090.  
  1091.         switch (wParam) {
  1092.             case '\r': TakeCareOfThings(f, TRUE);
  1093.                        CharInput(f, shift ? '\n' : '\r');
  1094.                        break;
  1095.  
  1096.             case '\t': if (f->type & FN_NORMAL) {
  1097.                             CharInput(f, wParam);
  1098.                        }
  1099.                        break;
  1100.  
  1101.             case '\b': CharInput(f, wParam);
  1102.                        break;
  1103.  
  1104.             default:   if (wParam > 26 /* ^Z */) {
  1105.                             CharInput (f, wParam);
  1106.                             //TakeCareOfThings(f, FALSE);
  1107.                             break;
  1108.                        }
  1109.                        j = 'A' + (wParam - 1);
  1110.  
  1111.                        i = DecodeKeyStroke(WM_CHAR, j, shift, ctrl);
  1112.                        if (i <= 0) {
  1113.                             MessageBeep(0); break;
  1114.                        }
  1115.                        switch (i) {
  1116.                             case IDM_KANJICONVERT:
  1117.                             case IDM_KANJILCONVERT:
  1118.                                 if (shift) i = IDM_KANJILCONVERT;
  1119.                                 SendMessage(hwnd, WM_COMMAND, i, 0L);
  1120.                                 return (0);
  1121.                             case IDM_CONTINUESEARCH:
  1122.                                 if (!(f->type & FN_NORMAL)) {
  1123.                                     MessageBeep(0);
  1124.                                     return (0);
  1125.                                 }
  1126.                                 SendMessage(global.hwnd, WM_COMMAND, i, 0L);
  1127.                                 return (0);
  1128.                             case IDM_TOGGLEMODE: /* These ones can operate in an edit control */
  1129.                             case IDM_KANJIINFO:
  1130.                             case IDM_KANJIINPUT:
  1131.                             case IDM_KANJILOOKUP:
  1132.                             case IDM_KANJITABLE:
  1133.                                 curfile = f;
  1134.                                 SendMessage(hwnd, WM_COMMAND, i, 0L);
  1135.                                 return (0);
  1136.                             default:
  1137.                                 if (!(f->type & FN_NORMAL)) {
  1138.                                     MessageBeep(0);
  1139.                                     return (0);
  1140.                                 }
  1141.                                 j = GetMenuState(hmenu, i, MF_BYCOMMAND);
  1142.                                 if (j & MF_GRAYED || j & MF_DISABLED) {
  1143.                                 } else {
  1144.                                     SendMessage(global.hwnd, WM_COMMAND, i, 0L);
  1145.                                     return (0);
  1146.                                 }
  1147.                                 break;
  1148.                        }
  1149.                        break;
  1150.  
  1151.         }
  1152.         break;
  1153.  
  1154.     case WM_KEYDOWN:
  1155.         if (capturing) return (0);
  1156.  
  1157.         /* Get the Key States */
  1158.  
  1159.         shift = (GetKeyState(VK_SHIFT) < 0);
  1160.         ctrl = (GetKeyState(VK_CONTROL) < 0);
  1161.  
  1162. KeyDown:
  1163.  
  1164.         /* Is the caret currently in the window? */
  1165.  
  1166.         if (!f->caret) MoveIntoWindow(f);
  1167.  
  1168.  
  1169.         switch (wParam) {
  1170.  
  1171.         case VK_HOME:
  1172.             if (!f->caret) {
  1173.                 InvalidateRect(hwnd, NULL, TRUE);
  1174.                 UpdateWindow(hwnd);
  1175.             }
  1176.  
  1177.             if (!shift) {
  1178.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1179.                 CharInput(f, '\0');
  1180.             } else {
  1181.                 CharInput(f, '\0'); CharInput(f, '\0');
  1182.                 RecordAnchor(f, f->current, f->cursor);
  1183.             }
  1184.  
  1185.             if (ctrl) {
  1186.                 if (CURLINE(f) == f->paragraph->lines) return (0);
  1187.  
  1188.                 /* Ctrl-Home: Go to BOF */
  1189.                 CURPARA(f) = f->paragraph;
  1190.                 CURLINE(f) = f->paragraph->lines;
  1191.                 CURCHAR(f) = 0;
  1192.                 f->startx = 0;
  1193.                 SetHorzScroll(f);
  1194.  
  1195.                 if (TOPLINE(f) != f->paragraph->lines) {
  1196.                     if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1197.                     SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0L);
  1198.                     f->pseudo = f->cursor;
  1199.                 } else {
  1200.                     FindCaret (f, TRUE);
  1201.                     f->pseudo = f->cursor;
  1202.                     if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1203.                     if (shift) ExtendSelection(hwnd, f);
  1204.                 }
  1205.             } else {
  1206.                 /* Home: Go to BOL */
  1207.  
  1208.                 if (CURCHAR(f) > 0) {
  1209.                     CURCHAR(f) = 0;
  1210.                     CURX(f) = PSEUDOX(f) = global.cpos[POS2ABS(f->current)].x;
  1211.  
  1212.                     if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1213.  
  1214.                     if (!f->caret || f->startx > 0) {
  1215.                         f->startx = 0;
  1216.                         SetHorzScroll(f);
  1217.                         InvalidateRect(hwnd, NULL, TRUE);
  1218.                         UpdateWindow(hwnd);
  1219.                     } else if (shift) {
  1220.                         ExtendSelection(hwnd, f);
  1221.                     }
  1222.                 }
  1223.             }
  1224.             break;
  1225.  
  1226.         case VK_END:
  1227.             if (!f->caret) {
  1228.                 InvalidateRect(hwnd, NULL, TRUE);
  1229.                 UpdateWindow(hwnd);
  1230.             }
  1231.  
  1232.             if (!shift) {
  1233.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1234.                 CharInput(f, '\0');
  1235.             } else {
  1236.                 CharInput(f, '\0'); CharInput(f, '\0');
  1237.                 RecordAnchor(f, f->current, f->cursor);
  1238.             }
  1239.  
  1240.             if (ctrl) {
  1241.                 if (CURLINE(f) == f->eof->lastline) return (0);
  1242.  
  1243.                 /* Ctrl-End: Go to EOF */
  1244.                 CURPARA(f) = f->eof;
  1245.                 CURLINE(f) = f->eof->lastline;
  1246.  
  1247.                 CURCHAR(f) = CURLINE(f)->length;
  1248.                 CURX(f) = CURLINE(f)->width - f->startx;
  1249.  
  1250.                 if (shift) DropAnchor(f, f->current, f->cursor, +1);
  1251.                 if (CURX(f) < 0 || CURX(f) >= f->width) MoveIntoWindow(f);
  1252.                 SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
  1253.                 f->pseudo = f->cursor;
  1254.             } else {
  1255.                 /* End: Go to EOL */
  1256.  
  1257.                 if (CURCHAR(f) < CURLINE(f)->length) {
  1258.                     CURCHAR(f) = CURLINE(f)->length;
  1259.                     PSEUDOX(f) = CURX(f) = CURLINE(f)->width - f->startx;
  1260.  
  1261.                     if (shift) DropAnchor(f, f->current, f->cursor, +1);
  1262.  
  1263.                     if (CURX(f) < 0 || CURX(f) >= f->width) {
  1264.                         MoveIntoWindow(f);
  1265.                         InvalidateRect(hwnd, NULL, TRUE);
  1266.                         UpdateWindow(hwnd);
  1267.                     } else if (!f->caret) {
  1268.                         InvalidateRect(hwnd, NULL, TRUE);
  1269.                         UpdateWindow(hwnd);
  1270.                     } else if (shift) {
  1271.                         ExtendSelection(hwnd, f);
  1272.                     }
  1273.                 }
  1274.             }
  1275.             break;
  1276.  
  1277.         case VK_PRIOR:
  1278.             if (!f->caret) {
  1279.                 InvalidateRect(hwnd, NULL, TRUE);
  1280.                 UpdateWindow(hwnd);
  1281.             }
  1282.  
  1283.             if (!shift) {
  1284.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1285.                 CharInput(f, '\0');
  1286.             } else {
  1287.                 CharInput(f, '\0'); CharInput(f, '\0');
  1288.                 RecordAnchor(f, f->current, f->cursor);
  1289.             }
  1290.  
  1291.             if (ctrl) {
  1292.                 /* Ctrl-PgUp: Go to BOS */
  1293.  
  1294. CtrlPgUp:       if (CURPARA(f) == TOPPARA(f) && CURLINE(f) == TOPLINE(f))
  1295.                     return (0);
  1296.  
  1297.                 f->current = f->top;
  1298.                 CURY(f) = CURLINE(f)->height + LINEGAP(f);
  1299.  
  1300.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1301.                 MatchPseudo(f, TRUE, FALSE);
  1302.  
  1303.                 if (shift) {
  1304.                     DropAnchor(f, f->current, f->cursor, -1);
  1305.                     ExtendSelection(hwnd, f);
  1306.                 }
  1307.  
  1308.                 PSEUDOY(f) = CURY(f);
  1309.             } else {
  1310.                 /* PgUp: Go to Previous page */
  1311.  
  1312.                 if (TOPPARA(f) == f->paragraph &&
  1313.                     TOPLINE(f) == f->paragraph->lines) goto CtrlPgUp;
  1314.  
  1315.                 p = f->top;
  1316.                 i = LINEGAP(f);
  1317.                 do {
  1318.                     i += LINEOF(p)->height;
  1319.                     if (i + LINEGAP(f) > f->height) break;
  1320.                     (f->vscroll)--;
  1321.                     i += PARAOF(p)->spacing;
  1322.                 } while (PREVLINE(p));
  1323.  
  1324.                 if ((f->type & FN_NORMAL) && !(f->type & FN_NOSCROLLBARS)) {
  1325.                     SetScrollPos(f->parent, SB_VERT, f->vscroll, TRUE);
  1326.                 }
  1327.  
  1328.                 f->top = p;
  1329.                 MatchPseudo(f, FALSE, TRUE);
  1330.  
  1331.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1332.                 MatchPseudo(f, TRUE, FALSE);
  1333.  
  1334.                 if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1335.                 InvalidateRect(hwnd, NULL, TRUE);
  1336.                 break;
  1337.             }
  1338.             break;
  1339.  
  1340.  
  1341.         case VK_NEXT:
  1342.             if (!f->caret) {
  1343.                 InvalidateRect(hwnd, NULL, TRUE);
  1344.                 UpdateWindow(hwnd);
  1345.             }
  1346.  
  1347.             if (!shift) {
  1348.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1349.                 CharInput(f, '\0');
  1350.             } else {
  1351.                 CharInput(f, '\0'); CharInput(f, '\0');
  1352.                 RecordAnchor(f, f->current, f->cursor);
  1353.             }
  1354.  
  1355.             if (ctrl) {
  1356.                 /* Ctrl-PgDn: Go to EOS */
  1357.  
  1358.                 p = f->top;
  1359.                 j = LINEGAP(f);         /* Vertical height */
  1360.  
  1361.                 scrolled = TRUE;
  1362.  
  1363.                 for (;;) {
  1364.                     j += LINEOF(p)->height;
  1365.                     if (j + LINEGAP(f) > f->height) break;
  1366.                     if (!NEXTLINE(p)) {
  1367.                         scrolled = FALSE;
  1368.                         break;
  1369.                     }
  1370.                     j += PARAOF(p)->spacing;
  1371.                 }
  1372.  
  1373.                 /* Move back to the previous line? */
  1374.  
  1375.                 if (scrolled) {
  1376.                     PREVLINE(p);
  1377.  
  1378.                     j -= LINEOF(p)->height + PARAOF(p)->spacing;
  1379.                     if (j < 0) j = -(PARAOF(p)->spacing - LINEGAP(f));
  1380.                 }
  1381.  
  1382.                 f->current = p;
  1383.  
  1384.                 CURY(f) = j;
  1385.  
  1386.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1387.                 MatchPseudo(f, TRUE, FALSE);
  1388.  
  1389.                 if (shift) {
  1390.                     DropAnchor(f, f->current, f->cursor, +1);
  1391.                     ExtendSelection(hwnd, f);
  1392.                 }
  1393.  
  1394.                 PSEUDOY(f) = CURY(f);
  1395.             } else {
  1396.                 /* PgDn: Go to Next page */
  1397.  
  1398.                 p = f->top;
  1399.                 i = LINEGAP(f);
  1400.                 do {
  1401.                     i += LINEOF(p)->height;
  1402.                     if (i + LINEGAP(f) > f->height) break;
  1403.                     (f->vscroll)++;
  1404.                     i += PARAOF(p)->spacing;
  1405.                 } while (NEXTLINE(p));
  1406.  
  1407.                 f->top = p;
  1408.                 MatchPseudo(f, FALSE, FALSE);
  1409.  
  1410.                 if ((f->type & FN_NORMAL) && !(f->type & FN_NOSCROLLBARS)) {
  1411.                     SetScrollPos(f->parent, SB_VERT, f->vscroll, TRUE);
  1412.                 }
  1413.  
  1414.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1415.                 MatchPseudo(f, TRUE, FALSE);
  1416.  
  1417.                 if (shift) DropAnchor(f, f->current, f->cursor, +1);
  1418.                 InvalidateRect(hwnd, NULL, TRUE);
  1419.             }
  1420.             break;
  1421.  
  1422.         case VK_UP:
  1423.             if (!f->caret) {
  1424.                 InvalidateRect(hwnd, NULL, TRUE);
  1425.                 UpdateWindow(hwnd);
  1426.             }
  1427.  
  1428.             if (!shift) {
  1429.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1430.                 CharInput(f, '\0');
  1431.             } else {
  1432.                 CharInput(f, '\0'); CharInput(f, '\0');
  1433.                 RecordAnchor(f, f->current, f->cursor);
  1434.             }
  1435.  
  1436.             i = CURLINE(f)->height;
  1437.  
  1438.             if (!PREVLINE(f->current)) break;
  1439.  
  1440.             if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1441.  
  1442.             CURY(f) -= i + CURPARA(f)->spacing;
  1443.  
  1444.             MatchPseudo(f, TRUE, FALSE);
  1445.  
  1446.             if (CURY(f) - CURLINE(f)->height - LINEGAP(f) < 0) {
  1447.                 DELAYCARET(TRUE);
  1448.                 SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0L);
  1449.                 RESTORECARET();
  1450.             }
  1451.  
  1452.             if (shift && !CaretDelayed) {
  1453.                 DropAnchor(f, f->current, f->cursor, -1);
  1454.                 ExtendSelection(hwnd, f);
  1455.             }
  1456.  
  1457.             PSEUDOY(f) = CURY(f);
  1458.             break;
  1459.  
  1460.         case VK_DOWN:
  1461.             if (!f->caret) {
  1462.                 InvalidateRect(hwnd, NULL, TRUE);
  1463.                 UpdateWindow(hwnd);
  1464.             }
  1465.  
  1466.             if (!shift) {
  1467.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1468.                 CharInput(f, '\0');
  1469.             } else {
  1470.                 CharInput(f, '\0'); CharInput(f, '\0');
  1471.                 RecordAnchor(f, f->current, f->cursor);
  1472.             }
  1473.  
  1474.             i = CURPARA(f)->spacing;
  1475.  
  1476.             if (!NEXTLINE(f->current)) break;
  1477.  
  1478.             if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1479.             CURY(f) += CURLINE(f)->height + i;
  1480.  
  1481.             MatchPseudo(f, TRUE, FALSE);
  1482.  
  1483.             while (CURY(f) + LINEGAP(f) > f->height) {
  1484.                 DELAYCARET(TRUE);
  1485.                 SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0L);
  1486.                 RESTORECARET();
  1487.             }
  1488.  
  1489.             if (shift && !CaretDelayed) {
  1490.                 DropAnchor(f, f->current, f->cursor, +1);
  1491.                 ExtendSelection(hwnd, f);
  1492.             }
  1493.  
  1494.             PSEUDOY(f) = CURY(f);
  1495.             break;
  1496.  
  1497.         case VK_LEFT:
  1498.             if (!f->caret) {
  1499.                 InvalidateRect(hwnd, NULL, TRUE);
  1500.                 UpdateWindow(hwnd);
  1501.             }
  1502.  
  1503.             if (!shift) {
  1504.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1505.                 CharInput(f, '\0');
  1506.             } else {
  1507.                 CharInput(f, '\0'); CharInput(f, '\0');
  1508.                 RecordAnchor(f, f->current, f->cursor);
  1509.             }
  1510.  
  1511.             if (!f->caret) {
  1512.                 InvalidateRect(hwnd, NULL, TRUE);
  1513.                 UpdateWindow(hwnd);
  1514.             }
  1515.  
  1516.             if (ctrl) {
  1517.                 CURCHAR(f)--;
  1518.  
  1519.                 while (CURCHAR(f) < 0) {
  1520.                     if (!PREVLINE(f->current)) {
  1521.                         CURCHAR(f) = 0;
  1522.                         break;
  1523.                     }
  1524.                     CURCHAR(f) = CURLINE(f)->length - 1;
  1525.                 }
  1526.  
  1527.                 OldCharType = GetCharType(CHAROF(f->current, CURCHAR(f)));
  1528.  
  1529.                 /* Skip to the beginning */
  1530.  
  1531.                 do {
  1532.                     CURCHAR(f)--;
  1533.  
  1534.                     if (CURCHAR(f) < 0) break;
  1535.                     NewCharType = GetCharType(CHAROF(f->current, CURCHAR(f)));
  1536.  
  1537.                     if (OldCharType == 0) OldCharType = NewCharType;
  1538.                 } while (NewCharType == OldCharType);
  1539.  
  1540.                 CURCHAR(f)++;
  1541.                 if (CURCHAR(f) >= CURLINE(f)->length) {
  1542.                     if (NEXTLINE(f->current)) CURCHAR(f) = 0;
  1543.                 }
  1544.  
  1545.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1546.  
  1547.                 r = FindCaret(f, FALSE);
  1548.  
  1549.                 if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1550.  
  1551.                 if (!r) {
  1552.                     MoveIntoWindow(f);
  1553.                     InvalidateRect(hwnd, NULL, TRUE);
  1554.                     UpdateWindow(hwnd);
  1555.                 } else if (shift) {
  1556.                     ExtendSelection(hwnd, f);
  1557.                 }
  1558.  
  1559.                 f->pseudo = f->cursor;
  1560.             } else {
  1561.                 if (CURCHAR(f) == 0) {
  1562.                     if (CURPARA(f)->prev == NULL && CURLINE(f)->prev == NULL)
  1563.                         return (0);
  1564.  
  1565.                     DELAYCARET(TRUE);
  1566.                     SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0L);
  1567.                     RESTORECARET();
  1568.  
  1569.                     if (shift && CURLINE(f)->length > 0) {
  1570.                         CURCHAR(f) = CURLINE(f)->length - 1;
  1571.                         CURX(f) = global.cpos[POS2ABS(f->current)].x;
  1572.                     } else {
  1573.                         CURCHAR(f) = CURLINE(f)->length;
  1574.                         CURX(f) = CURLINE(f)->width - f->startx;
  1575.                     }
  1576.                 } else {
  1577.                     (CURCHAR(f))--;
  1578.                     if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1579.                     CURX(f) = global.cpos[POS2ABS(f->current)].x;
  1580.                 }
  1581.  
  1582.                 if (shift) DropAnchor(f, f->current, f->cursor, -1);
  1583.  
  1584.                 if (CURX(f) < 0 || CURX(f) >= f->width) {
  1585.                     MoveIntoWindow(f);
  1586.                     InvalidateRect(hwnd, NULL, TRUE);
  1587.                     UpdateWindow(hwnd);
  1588.                 } else if (shift) {
  1589.                     ExtendSelection(hwnd, f);
  1590.                 }
  1591.  
  1592.                 PSEUDOX(f) = CURX(f);
  1593.             }
  1594.             break;
  1595.  
  1596.         case VK_RIGHT:
  1597.             if (!f->caret) {
  1598.                 InvalidateRect(hwnd, NULL, TRUE);
  1599.                 UpdateWindow(hwnd);
  1600.             }
  1601.  
  1602.             if (!shift) {
  1603.                 TakeCareOfThings(f, TRUE); //SELNOW(f));
  1604.                 CharInput(f, '\0');
  1605.             } else {
  1606.                 CharInput(f, '\0'); CharInput(f, '\0');
  1607.                 RecordAnchor(f, f->current, f->cursor);
  1608.             }
  1609.  
  1610.             if (!f->caret) {
  1611.                 InvalidateRect(hwnd, NULL, TRUE);
  1612.                 UpdateWindow(hwnd);
  1613.             }
  1614.  
  1615.             if (ctrl) {
  1616.                 OldCharType = GetCharType(CHAROF(f->current, CURCHAR(f)));
  1617.  
  1618.                 do {
  1619.                     CURCHAR(f)++;
  1620.                     if (CURCHAR(f) >= CURLINE(f)->length) {
  1621.                         if (!NEXTLINE(f->current)) {
  1622.                             CURCHAR(f) = CURLINE(f)->length;
  1623.                             break;
  1624.                         }
  1625.                         CURCHAR(f) = 0;
  1626.                     }
  1627.  
  1628.                     NewCharType = GetCharType(CHAROF(f->current, CURCHAR(f)));
  1629.  
  1630.                     if (NewCharType == 0)   /* Will not stop for white spaces */
  1631.                         OldCharType = NewCharType;
  1632.  
  1633.                 } while (NewCharType == OldCharType);
  1634.  
  1635.                 if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1636.  
  1637.                 r = FindCaret(f, FALSE);
  1638.  
  1639.                 if (shift) DropAnchor(f, f->current, f->cursor, +1);
  1640.  
  1641.                 if (!r) {
  1642.                     MoveIntoWindow(f);
  1643.                     InvalidateRect(hwnd, NULL, TRUE);
  1644.                     UpdateWindow(hwnd);
  1645.                 } else if (shift) {
  1646.                     ExtendSelection(hwnd, f);
  1647.                 }
  1648.  
  1649.                 f->pseudo = f->cursor;
  1650.             } else {
  1651.                 if (CURCHAR(f) >= CURLINE(f)->length) {
  1652.                     if (CURPARA(f)->next == NULL && CURLINE(f)->next == NULL)
  1653.                         return (0);
  1654.  
  1655.                     DELAYCARET(TRUE);
  1656.                     SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0L);
  1657.                     RESTORECARET();
  1658.  
  1659.                     if (shift && CURLINE(f)->length > 0) {
  1660.                         CURCHAR(f) = 1;
  1661.                     } else {
  1662.                         CURCHAR(f) = 0;
  1663.                     }
  1664.                     CURX(f) = global.cpos[POS2ABS(f->current)].x;
  1665.                 } else {
  1666.                     if (CURCHAR(f) + 1 >= CURLINE(f)->length) {
  1667.                         CURX(f) = CURLINE(f)->width - f->startx;
  1668.                     } else {
  1669.                         if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1670.                         CURX(f) = global.cpos[POS2ABS(f->current) + 1].x;
  1671.                     }
  1672.                     CURCHAR(f)++;
  1673.                 }
  1674.  
  1675.                 if (shift) DropAnchor(f, f->current, f->cursor, +1);
  1676.  
  1677.                 if (CURX(f) < 0 || CURX(f) >= f->width) {
  1678.                     MoveIntoWindow(f);
  1679.                     InvalidateRect(hwnd, NULL, TRUE);
  1680.                     UpdateWindow(hwnd);
  1681.                 } else if (shift) {
  1682.                     ExtendSelection(hwnd, f);
  1683.                 }
  1684.  
  1685.                 PSEUDOX(f) = CURX(f);
  1686.             }
  1687.             break;
  1688.  
  1689.         case VK_INSERT:
  1690.             if (!f->caret) {
  1691.                 InvalidateRect(hwnd, NULL, TRUE);
  1692.                 UpdateWindow(hwnd);
  1693.             }
  1694.  
  1695.             if (shift && !ctrl) InsertFromClipboard(f);
  1696.             if (ctrl && !shift) CopyToClipboard(f);
  1697.             break;
  1698.  
  1699.         case VK_DELETE:
  1700.             if (!f->caret) {
  1701.                 InvalidateRect(hwnd, NULL, TRUE);
  1702.                 UpdateWindow(hwnd);
  1703.             }
  1704.  
  1705.             if (shift && !ctrl && SELPARA1(f) != NULL) CopyToClipboard(f);
  1706.             CharInput(f, 127);
  1707.             break;
  1708.  
  1709.         default:
  1710.             i = DecodeKeyStroke(WM_KEYDOWN, wParam, shift, ctrl);
  1711.             if (i <= 0) {
  1712.                 if (wParam >= VK_F1 && wParam <= VK_F12) MessageBeep(0);
  1713.                 return (0);
  1714.             }
  1715.             switch (i) {
  1716.                 case IDM_KANJICONVERT:
  1717.                 case IDM_KANJILCONVERT:
  1718.                     if (shift) i = IDM_KANJILCONVERT;
  1719.                     SendMessage(hwnd, WM_COMMAND, i, 0L);
  1720.                     return (0);
  1721.                 case IDM_CONTINUESEARCH:
  1722.                     if (!(f->type & FN_NORMAL)) {
  1723.                         MessageBeep(0);
  1724.                         return (0);
  1725.                     }
  1726.                     SendMessage(global.hwnd, WM_COMMAND, i, 0L);
  1727.                     return (0);
  1728.                 case IDM_TOGGLEMODE: /* These ones can operate in an edit control */
  1729.                 case IDM_KANJIINFO:
  1730.                 case IDM_KANJIINPUT:
  1731.                 case IDM_KANJILOOKUP:
  1732.                 case IDM_KANJITABLE:
  1733.                     curfile = f;
  1734.                     SendMessage(hwnd, WM_COMMAND, i, 0L);
  1735.                     return (0);
  1736.                 default:
  1737.                     if (!(f->type & FN_NORMAL)) {
  1738.                         MessageBeep(0);
  1739.                         return (0);
  1740.                     }
  1741.                     j = GetMenuState(hmenu, i, MF_BYCOMMAND);
  1742.                     if (j & MF_GRAYED || j & MF_DISABLED) {
  1743.                     } else {
  1744.                         SendMessage(global.hwnd, WM_COMMAND, i, 0L);
  1745.                        return (0);
  1746.                     }
  1747.                     break;
  1748.             }
  1749.             break;
  1750.         }
  1751.  
  1752.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  1753.  
  1754.         Triangles(f);
  1755.         return (0);
  1756.  
  1757.     case WM_VSCROLL:
  1758.         if (capturing) return (0);
  1759.         if (f->nr_lines - 1 <= 0) return (0);
  1760.  
  1761.         switch (wParam) {
  1762.  
  1763.         case SB_TOP:
  1764.             CURPARA(f) = TOPPARA(f) = f->paragraph;
  1765.             CURLINE(f) = TOPLINE(f) = f->paragraph->lines;
  1766.             f->vscroll = 0;
  1767.             InvalidateRect(hwnd, NULL, TRUE);
  1768.             FillCPos(f, CURPARA(f), 0, -1);
  1769.             break;
  1770.  
  1771.         case SB_BOTTOM:
  1772.             /* Go to the bottom */
  1773.             TOPPARA(f) = f->eof;
  1774.             TOPLINE(f) = f->eof->lastline;
  1775.             f->vscroll = f->nr_lines;
  1776.             InvalidateRect(hwnd, NULL, TRUE);
  1777.             FillCPos(f, CURPARA(f), 0, -1);
  1778.             break;
  1779.  
  1780.         case SB_LINEUP:
  1781.  
  1782.             if (!PREVLINE(f->top)) return (0);
  1783.             (f->vscroll)--;
  1784.  
  1785.             scrolled = TOPLINE(f)->height + TOPPARA(f)->spacing;
  1786.  
  1787.             if (CaretDelayed) HideCaret(hwnd);
  1788.             ScrollWindow(hwnd, 0, scrolled, NULL, NULL);
  1789.             if (CaretDelayed) ShowCaret(hwnd);
  1790.             ShiftCPos(f, 0, scrolled);     /* The rest filled by WM_PAINT */
  1791.             ChangeAnchor(0, scrolled);
  1792.             break;
  1793.  
  1794.         case SB_LINEDOWN:
  1795.             scrolled = TOPLINE(f)->height + TOPPARA(f)->spacing;
  1796.  
  1797.             if (!NEXTLINE(f->top)) return (0);
  1798.             (f->vscroll)++;
  1799.  
  1800.             if (CaretDelayed) HideCaret(hwnd);
  1801.             ScrollWindow(hwnd, 0, -scrolled, NULL, NULL);
  1802.             if (CaretDelayed) ShowCaret(hwnd);
  1803.             ShiftCPos(f, 0, -scrolled);     /* The rest filled by WM_PAINT */
  1804.             ChangeAnchor(0, -scrolled);
  1805.             break;
  1806.  
  1807.         case SB_PAGEUP:
  1808.             p = f->top;
  1809.             i = LINEGAP(f);
  1810.             do {
  1811.                 i += LINEOF(p)->height;
  1812.                 if (i + LINEGAP(f) > f->height) break;
  1813.                 (f->vscroll)--;
  1814.                 i += PARAOF(p)->spacing;
  1815.             } while (PREVLINE(p));
  1816.  
  1817.             f->top = p;
  1818.             InvalidateRect(hwnd, NULL, TRUE);
  1819.             FillCPos(f, CURPARA(f), 0, -1);
  1820.             break;
  1821.  
  1822.         case SB_PAGEDOWN:
  1823.             p = f->top;
  1824.             i = LINEGAP(f);
  1825.             do {
  1826.                 i += LINEOF(p)->height;
  1827.                 if (i + LINEGAP(f) > f->height) break;
  1828.                 (f->vscroll)++;
  1829.                 i += PARAOF(p)->spacing;
  1830.             } while (NEXTLINE(p));
  1831.  
  1832.             f->top = p;
  1833.             InvalidateRect(hwnd, NULL, TRUE);
  1834.             FillCPos(f, CURPARA(f), 0, -1);
  1835.             break;
  1836.  
  1837.         case SB_THUMBPOSITION:
  1838.             f->vscroll = LOWORD(lParam);
  1839.             i = 0;
  1840.             PARAOF(p) = f->paragraph;
  1841.             LINEOF(p) = f->paragraph->lines;
  1842.             do {
  1843.                if (i >= f->vscroll) break;
  1844.                i++;
  1845.             } while (NEXTLINE(p));
  1846.  
  1847.             f->top = p;
  1848.             InvalidateRect(hwnd, NULL, TRUE);
  1849.             FillCPos(f, CURPARA(f), 0, -1);
  1850.             break;
  1851.  
  1852.         default:
  1853.             return (0);
  1854.  
  1855.         }
  1856.  
  1857.         if (f->vscroll < 0) f->vscroll = 0;
  1858.         if (f->vscroll >= f->nr_lines) f->vscroll = f->nr_lines - 1;
  1859.         if ((f->type & FN_NORMAL) && !(f->type & FN_NOSCROLLBARS)) {
  1860.             SetScrollPos(f->parent, SB_VERT, f->vscroll, TRUE);
  1861.         }
  1862.         UpdateWindow(hwnd);
  1863.  
  1864.         Triangles(f);
  1865.         return (0);
  1866.  
  1867.  
  1868.     case WM_HSCROLL:
  1869.         if (capturing) return (0);
  1870.  
  1871.         switch (wParam) {
  1872.  
  1873.         case SB_TOP:
  1874.             f->startx = 0;
  1875.             InvalidateRect(hwnd, NULL, TRUE);
  1876.             FillCPos(f, CURPARA(f), 0, -1);
  1877.             break;
  1878.  
  1879.         case SB_BOTTOM:
  1880.             return (0);
  1881.  
  1882.         case SB_PAGEUP:
  1883.             i = f->width / BASEWIDTH(f);
  1884.             f->startx -= (i/2) * BASEWIDTH(f);
  1885.             if (f->startx < 0) f->startx = 0;
  1886.             InvalidateRect(hwnd, NULL, TRUE);
  1887.             FillCPos(f, CURPARA(f), 0, -1);
  1888.             break;
  1889.  
  1890.         case SB_PAGEDOWN:
  1891.             i = f->width / BASEWIDTH(f);
  1892.             f->startx += (i/2) * BASEWIDTH(f);
  1893.             InvalidateRect(hwnd, NULL, TRUE);
  1894.             FillCPos(f, CURPARA(f), 0, -1);
  1895.             break;
  1896.  
  1897.         case SB_LINEUP:
  1898.             if (f->startx <= 0) return (0);
  1899.             i = BASEWIDTH(f);
  1900.             f->startx -= i;
  1901.             ScrollWindow(hwnd, i, 0, NULL, NULL);
  1902.             ShiftCPos(f, -i, 0);
  1903.             break;
  1904.  
  1905.         case SB_LINEDOWN:
  1906.             i = BASEWIDTH(f);
  1907.             f->startx += i;
  1908.             ScrollWindow(hwnd, -i, 0, NULL, NULL);
  1909.             ShiftCPos(f, i, 0);
  1910.             break;
  1911.  
  1912.         case SB_THUMBPOSITION:
  1913.             f->startx = LOWORD(lParam) * BASEWIDTH(f);
  1914.             InvalidateRect(hwnd, NULL, TRUE);
  1915.             FillCPos(f, CURPARA(f), 0, -1);
  1916.             break;
  1917.  
  1918.         default:
  1919.             return (0);
  1920.         }
  1921.  
  1922.         UpdateWindow(hwnd);
  1923.  
  1924.         SetHorzScroll(f);
  1925.  
  1926.         if ((f->type & FN_NORMAL) && RULER(f).hwnd != NULL) {
  1927.             InvalidateRect(RULER(f).hwnd, NULL, TRUE);
  1928.             UpdateWindow(RULER(f).hwnd);
  1929.         }
  1930.         return (0);
  1931.  
  1932.     case WM_LBUTTONDBLCLK: {
  1933.         int cat;        /* 0 = space, 1 = kanji symbol, 2 = ASCII, 3 = kanji */
  1934.         POSITION p1, p2, ptemp;
  1935.  
  1936.         if (SELPARA1(f) != NULL) TurnOffSelection(f);
  1937.  
  1938.         /* Categorize them */
  1939.  
  1940.         cat = CategorizeChar(CHAROF(f->current, CURCHAR(f)));
  1941.  
  1942.         if (cat == 0) return (0);     /* No need to do anything */
  1943.  
  1944.         p1 = p2 = f->current;
  1945.  
  1946.         for (;;) {
  1947.             ptemp = p2;
  1948.             POSOF(ptemp)++;
  1949.             if (POSOF(ptemp) >= LINEOF(ptemp)->length) {
  1950.                 if (LINEOF(ptemp)->next != NULL) {
  1951.                     LINEOF(ptemp) = LINEOF(ptemp)->next;
  1952.                     POSOF(ptemp) = 0;
  1953.                 } else {
  1954.                     break;
  1955.                 }
  1956.             }
  1957.             if (CategorizeChar(CHAROF(ptemp, POSOF(ptemp))) !=cat) break;
  1958.             p2 = ptemp;
  1959.         }
  1960.  
  1961.         for (;;) {
  1962.             ptemp = p1;
  1963.             POSOF(ptemp)--;
  1964.             if (POSOF(ptemp) < 0) {
  1965.                 if (LINEOF(ptemp)->prev != NULL) {
  1966.                     LINEOF(ptemp) = LINEOF(ptemp)->prev;
  1967.                     POSOF(ptemp) = LINEOF(ptemp)->length - 1;
  1968.                 } else {
  1969.                     break;
  1970.                 }
  1971.             }
  1972.             if (CategorizeChar(CHAROF(ptemp, POSOF(ptemp))) !=cat) break;
  1973.             p1 = ptemp;
  1974.         }
  1975.  
  1976.         /* Select it */
  1977.  
  1978.         SELPARA1(f) = SELPARA2(f) = CURPARA(f);
  1979.         SELPOS1(f) = POS2ABS(p1);   SELPOS2(f) = POS2ABS(p2);
  1980.         SELTYPE(f) = SEL_SELECTION;
  1981.         FlipHighlight(f);
  1982.  
  1983.         f->current = p2;
  1984.         CURCHAR(f)++;
  1985.  
  1986.         if (FindCaret(f, FALSE))
  1987.             DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  1988.         else
  1989.             DoCaret(f, 0, 0, FALSE);
  1990.  
  1991.         return (0);
  1992.     }
  1993.  
  1994.     case WM_LBUTTONDOWN: {
  1995.         int x, y;
  1996.  
  1997.         if (!(f->type & FN_NORMAL)) {
  1998.             DELAYCARET(TRUE);
  1999.             SetFocus(hwnd);
  2000.             RESTORECARET();
  2001.         }
  2002.  
  2003.         shift = (GetKeyState(VK_SHIFT) < 0);
  2004.         TakeCareOfThings(f, TRUE); //shift);
  2005.  
  2006.         /* Find where he clicked... */
  2007.  
  2008.         x = PSEUDOX(f);
  2009.         y = PSEUDOY(f);
  2010.         PSEUDOX(f) = LOWORD(lParam);
  2011.         PSEUDOY(f) = HIWORD(lParam);
  2012.  
  2013.         if (shift) RecordAnchor(f, f->current, f->cursor);
  2014.  
  2015.         if (!MatchPseudo(f, FALSE, TRUE)) {
  2016.             PSEUDOX(f) = x;
  2017.             PSEUDOY(f) = y;
  2018.         } else {
  2019.             MatchPseudo(f, TRUE, FALSE);
  2020.         }
  2021.  
  2022.         if (global.cpospara != CURPARA(f)) FillCPos(f, CURPARA(f), 0, -1);
  2023.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  2024.  
  2025.         if (shift) {
  2026.             DropAnchor(f, f->current, f->cursor, 0);
  2027.             ExtendSelection(hwnd, f);
  2028.         }
  2029.  
  2030.         LastSeen = f->cursor;
  2031.         capturing = TRUE;
  2032.         SetCapture(hwnd);
  2033.         HideCaret(hwnd);
  2034.  
  2035.         return (0);
  2036.     }
  2037.  
  2038.     case WM_MOUSEMOVE:
  2039.         if (!capturing) return (0);
  2040.  
  2041.         RecordAnchor(f, f->current, f->cursor);
  2042.  
  2043.         /* Find where he moved to... */
  2044.  
  2045.         point.x = LOWORD(lParam);
  2046.         point.y = HIWORD(lParam);
  2047.  
  2048.         if (point.x < 0) point.x = 0;   if (point.x > f->width) point.x = f->width;
  2049.         if (point.y < 0) point.y = 0;   if (point.y > f->height) point.y = f->height;
  2050.  
  2051.         PSEUDOX(f) = point.x;
  2052.         PSEUDOY(f) = point.y;
  2053.  
  2054.         MatchPseudo(f, FALSE, FALSE);
  2055.         MatchPseudo(f, TRUE, FALSE);
  2056.  
  2057.         point.x = CURX(f);
  2058.         point.y = CURY(f);
  2059.  
  2060.         /* Actually moved? */
  2061.  
  2062.         if (point.x == LastSeen.x && point.y == LastSeen.y) return (0);
  2063.  
  2064.         LastSeen = point;
  2065.  
  2066.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  2067.  
  2068.         DropAnchor(f, f->current, f->cursor, 0);
  2069.         ExtendSelection(hwnd, f);
  2070.         return (0);
  2071.  
  2072.     case WM_LBUTTONUP:
  2073.         if (!capturing) return (0);
  2074.  
  2075.         ReleaseCapture();
  2076.         capturing = FALSE;
  2077.  
  2078.         Triangles(f);
  2079.  
  2080.         if (global.cpospara != CURPARA(f)) FillCPos(f, CURPARA(f), 0, -1);
  2081.         ShowCaret(hwnd);
  2082.         return (0);
  2083.  
  2084.     case WM_MOUSEACTIVATE:
  2085.         /* It is always followed by a WM_SETFOCUS */
  2086.         MouseActivated = TRUE;
  2087.  
  2088.         if (!(f->type & FN_NORMAL)) return (0);
  2089.  
  2090.         if (PrevWindow != hwnd && PrevWindow != f->parent && LOWORD(lParam) == HTCLIENT)
  2091.            return (MA_ACTIVATEANDEAT);
  2092.         else
  2093.            return (MA_ACTIVATE);
  2094.  
  2095.     case WM_PAINT:
  2096.         /* Now draw the window */
  2097.  
  2098.         Triangles(f);
  2099.         HideCaret(hwnd);
  2100.  
  2101.         hdc = BeginPaint(hwnd, &ps);
  2102.  
  2103.         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  2104.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  2105.  
  2106.         cliprect = ps.rcPaint;
  2107.         RedrawFile (f, hdc, 0, 0, &cliprect, global.showspecial);
  2108.  
  2109.         if (!(f->type & FN_NORMAL) || f == global.active) {
  2110.             if (FindCaret(f, FALSE))
  2111.                 DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  2112.             else
  2113.                 DoCaret(f, 0, 0, FALSE);
  2114.         }
  2115.  
  2116.         EndPaint(hwnd, &ps);
  2117.         ShowCaret(hwnd);
  2118.  
  2119.         return (0);
  2120.  
  2121.     case WM_SETFOCUS:
  2122.         CreateCaret(hwnd, NULL, CARETWIDTH, f->basefont->height + LINEGAP(f));
  2123.         f->caret = FALSE;
  2124.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  2125.  
  2126.         CharInput(f, '\0');
  2127.  
  2128.         if (f->type & FN_NORMAL) {
  2129.             for (f = fileoptions; f != NULL && f->hwnd != hwnd; f = f->next);
  2130.  
  2131.             global.active = f;
  2132.  
  2133.             for (f = fileoptions; f != NULL; f = f->next) {
  2134.                 if (f == global.active) continue;
  2135.                 TurnOffSelection(f);
  2136.             }
  2137.         } else if (!MouseActivated && GetParent((HWND) wParam) == GetParent(hwnd)) {
  2138.             /* A dialog control activated by the TAB key */
  2139.  
  2140.             i = unitlen(f->paragraph->text);
  2141.  
  2142.             if (i > 0) {
  2143.                 TurnOffSelection(f);
  2144.                 SELPARA1(f) = SELPARA2(f) = f->paragraph;
  2145.                 SELPOS1(f) = 0; SELPOS2(f) = i - 1;
  2146.                 SELTYPE(f) = SEL_SELECTION;
  2147.                 FlipHighlight(f);
  2148.  
  2149.                 CURCHAR(f) = i;
  2150.                 if (!FindCaret(f, TRUE)) {
  2151.                     MoveIntoWindow(f);
  2152.                     InvalidateRect(hwnd, NULL, TRUE);
  2153.                     UpdateWindow(hwnd);
  2154.                 }
  2155.                 DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  2156.             }
  2157.         }
  2158.  
  2159.         MouseActivated = FALSE;
  2160.         return (0);
  2161.  
  2162.     case WM_KILLFOCUS:
  2163.         if (!(f->type & FN_NORMAL) && GetParent((HWND) wParam) == GetParent(hwnd)) {
  2164.             /* A dialog control de-activated by TAB or mouse */
  2165.             /* Make sure it returns to the beginning */
  2166.  
  2167.             CURCHAR(f) = 0;
  2168.  
  2169.             if (SELPARA1(f) != NULL) {
  2170.                 if (f->startx == 0) FlipHighlight(f);
  2171.                 SELPARA1(f) = SELPARA2(f) = NULL;
  2172.                 SELPOS1(f) = SELPOS2(f) = 0;
  2173.                 SELNOW(f) = FALSE;
  2174.                 SELTYPE(f) = SEL_SELECTION;
  2175.             }
  2176.  
  2177.             if (f->startx != 0) {
  2178.                 f->startx = 0;
  2179.                 InvalidateRect(hwnd, NULL, TRUE);
  2180.             }
  2181.         }
  2182.  
  2183.         DoCaret(f, 0, 0, FALSE);
  2184.  
  2185.         DestroyCaret();
  2186.         return (0);
  2187.  
  2188.     case WM_DESTROY: {
  2189.         FILEOPTIONS *f1;
  2190.  
  2191.         CloseFile(f);
  2192.  
  2193.         /* Unlink it */
  2194.  
  2195.         if (f->type & FN_NORMAL) {
  2196.             if (fileoptions == f) {
  2197.                 fileoptions = f->next;
  2198.             } else {
  2199.                 for (f1 = fileoptions; f1 != NULL && f1->next != f; f1 = f1->next);
  2200.                 if (f1 == NULL) {
  2201.                     ErrorMessage(global.hwnd, "Funny: cannot find FILEOPTIONS record to deallocate");
  2202.                 } else {
  2203.                     f1->next = f->next;
  2204.                 }
  2205.             }
  2206.  
  2207.             if (fileoptions == NULL) {
  2208.                 SwitchMenu(1);     /* Minimal */
  2209.                 global.active = NULL;
  2210.             }
  2211.         }
  2212.  
  2213.         FreeMem(f);
  2214.         return (0);
  2215.     }
  2216.  
  2217.     }
  2218.  
  2219.     return (DefWindowProc(hwnd, message, wParam, lParam));
  2220. }
  2221.  
  2222.  
  2223.  
  2224. LONG FAR PASCAL FileParentWinProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  2225. {
  2226.     FILEOPTIONS *f;
  2227.  
  2228.  
  2229.     if (IsIconic(hwnd)) return(DefMDIChildProc(hwnd, message, wParam, lParam));
  2230.  
  2231.     f = (FILEOPTIONS *) GetWindowWord(hwnd, 0);
  2232.  
  2233.     switch (message) {
  2234.         case WM_CREATE:
  2235.             SetWindowWord(hwnd, 0, (WORD) curfile);
  2236.             break;
  2237.  
  2238.         case WM_SIZE:
  2239.             if (RULER(f).hwnd) {
  2240.                 MoveWindow(RULER(f).hwnd, 0, 0,
  2241.                             LOWORD(lParam), RULERHEIGHT, TRUE);
  2242.             }
  2243.             if (f->hwnd != NULL) {
  2244.                 MoveWindow(f->hwnd, BORDERSPACE, BORDERSPACE + THERULER(f),
  2245.                            LOWORD(lParam) - BORDERSPACE,
  2246.                            HIWORD(lParam) - BORDERSPACE - THERULER(f), TRUE);
  2247.             }
  2248.             break;
  2249.  
  2250.         case WM_KEYDOWN:
  2251.         case WM_CHAR:
  2252.         case WM_VSCROLL:
  2253.         case WM_HSCROLL:
  2254.         case WM_SETFOCUS:
  2255.         case WM_KILLFOCUS:
  2256.             SendMessage(f->hwnd, message, wParam, lParam);
  2257.             break;
  2258.  
  2259.         case WM_MDIACTIVATE:
  2260.             if (!(f->type & FN_NORMAL)) return (0);
  2261.             if (wParam) {
  2262.                 /* Save handle of window losing activity */
  2263.                 PrevWindow = HIWORD(lParam);
  2264.                 if (PrevWindow == NULL) PrevWindow = hwnd;
  2265.             } else {
  2266.                 /* Deactivating window */
  2267.                 PrevWindow = NULL;
  2268.             }
  2269.             break;
  2270.  
  2271.         case WM_SETCURSOR:
  2272.             if (!(f->type & FN_NORMAL)) return (0);
  2273.             PrevWindow = hwnd;
  2274.             break;
  2275.  
  2276.         case WM_CLOSE:
  2277.         case WM_QUERYENDSESSION:
  2278.             if (f->changed) {
  2279.                 char name[MAXLINELEN];
  2280.                 char buffer[MAXLINELEN];
  2281.  
  2282.                 if (!f->filename[0]) {
  2283.                     GetWindowText(hwnd, name, 50);
  2284.                     sprintf(buffer, "Close File: %s", name);
  2285.                 } else {
  2286.                     sprintf(buffer, "Close File: %s", f->filename);
  2287.                 }
  2288.  
  2289.                 MessageBeep(0);
  2290.  
  2291.                 if (IDOK != MessageBox (hwnd,
  2292.                     "You have made additional changes\n"
  2293.                     "to this file since you last saved it.\n"
  2294.                     "Closing the file now will lose these\n"
  2295.                     "changes!\n"
  2296.                     "\n"
  2297.                     "Do you REALLY want to close this\n"
  2298.                     "file and lose your changes?",
  2299.                     buffer, MB_ICONQUESTION | MB_OKCANCEL))
  2300.                         return (FALSE);
  2301.             }
  2302.             return (TRUE);
  2303.     }
  2304.  
  2305.     return (DefMDIChildProc(hwnd, message, wParam, lParam));
  2306. }
  2307.  
  2308.  
  2309.  
  2310. int CalcLineLength (FILEOPTIONS *f)
  2311. {
  2312.     int margindots, linelen;
  2313.     double charsize;
  2314.  
  2315.     charsize = (double) (PRINTFONT->width + PRINTFONT->leading) * global.printscale;
  2316.     charsize *= (double) global.resolution.x / (double) global.resolution.y;
  2317.  
  2318.     margindots = (f->pagesetup.margins[0] + f->pagesetup.margins[1]) * global.resolution.x;
  2319.     linelen = (int) floor(((global.paper[0] * global.resolution.x) - margindots) / charsize);
  2320.  
  2321.     return (linelen);
  2322. }
  2323.  
  2324.  
  2325.  
  2326. FILEOPTIONS *NewFile (int type, BOOL allocate)
  2327. {
  2328.     FILEOPTIONS *f;
  2329.     PARAGRAPH far *p;
  2330.     ONELINE far *lp;
  2331.  
  2332.  
  2333.     f = (FILEOPTIONS *) MemAlloc(sizeof(FILEOPTIONS));
  2334.     if (f == NULL) return (NULL);
  2335.  
  2336.     if (type & FN_NORMAL) {
  2337.         f->next = fileoptions;
  2338.         fileoptions = f;
  2339.  
  2340.         f->leading = global.leading;
  2341.         f->spacing = global.spacing;
  2342.         f->basefont = BASEFONT;
  2343.         f->pagesetup = global.pagesetup;
  2344.  
  2345.         f->linelen = CalcLineLength(f);
  2346.     } else {
  2347.         f->next = NULL;
  2348.  
  2349.         f->leading = SYSFONT->leading;
  2350.         f->spacing = SYSFONT->spacing;
  2351.         f->basefont = SYSFONT;
  2352.  
  2353.         f->linelen = 1000;        /* The caller should set it later */
  2354.     }
  2355.  
  2356.     curfile = f;
  2357.  
  2358.     f->nr_bytes = 0L;
  2359.     f->fileformat = FF_NORMAL;
  2360.     f->type = type;
  2361.     f->undo = f->undotail = f->redo = f->redotail = NULL;
  2362.     f->undolevels = 0;
  2363.  
  2364.     /* Allocate one paragraph and one line */
  2365.  
  2366.     if (!allocate) {
  2367.         f->paragraph = f->eof = NULL;
  2368.         TOPPARA(f) = CURPARA(f) = NULL;
  2369.         TOPLINE(f) = CURLINE(f) = NULL;
  2370.         CURCHAR(f) = 0;
  2371.  
  2372.         f->nr_lines = 0;
  2373.     } else {
  2374.         f->paragraph = f->eof = p = StructAlloc(PARAGRAPH);
  2375.         p->prev = p->next = NULL;
  2376.         p->leftindent = p->firstindent = p->rightindent = 0;
  2377.         p->spacing = f->spacing;
  2378.         p->spacemulti = 100;
  2379.         p->text = (UNIT far *) BlockAlloc(FIRSTBLOCKSIZE);
  2380.         p->textsize = FIRSTBLOCKSIZE / sizeof(UNIT);
  2381.         p->text[0].kanji = 0;
  2382.  
  2383.         lp = p->lines = p->lastline = StructAlloc(ONELINE);
  2384.         lp->next = lp->prev = NULL;
  2385.         lp->position = 0;
  2386.         lp->height = f->basefont->height;
  2387.         lp->length = lp->width = 0;
  2388.  
  2389.         TOPPARA(f) = CURPARA(f) = f->paragraph;
  2390.         TOPLINE(f) = CURLINE(f) = f->paragraph->lines;
  2391.         CURCHAR(f) = 0;
  2392.  
  2393.         f->nr_lines = 1;
  2394.     }
  2395.  
  2396.     CURX(f) = PSEUDOX(f) = 0;
  2397.     CURY(f) = PSEUDOY(f) = f->basefont->height + 2;
  2398.     f->caret = FALSE;
  2399.     f->changed = FALSE;
  2400.  
  2401.     f->vscroll = f->hscroll = 0;
  2402.     f->hdc = NULL;
  2403.  
  2404.     f->hwnd = f->parent = NULL;
  2405.     f->startx = 0;
  2406.     f->relaxmargin = global.relaxmargin;
  2407.  
  2408.     RULER(f).hwnd = NULL;
  2409.     RULER(f).smallticks = AVGHEIGHT / 3;
  2410.     if (RULER(f).smallticks <= 0) RULER(f).smallticks = 1;
  2411.     RULER(f).bigticks = 2 * RULER(f).smallticks;
  2412.     RULER(f).upperrow = 3 * RULER(f).smallticks - 1;
  2413.     RULER(f).lowerrow = RULERHEIGHT - 1;
  2414.     RULER(f).middlerow = (RULERHEIGHT + RULER(f).upperrow) / 2;
  2415.     RULER(f).pointer = (f->basefont->width + f->leading) / 3;
  2416.  
  2417.     if (RULER(f).pointer > AVGWIDTH) RULER(f).pointer = AVGWIDTH;
  2418.  
  2419.     RULER(f).startx = 0;
  2420.  
  2421.     SELNOW(f) = FALSE;
  2422.     SELPARA1(f) = SELPARA2(f) = NULL;
  2423.     SELPOS1(f) = SELPOS2(f) = 0;
  2424.     SELTYPE(f) = SEL_CONVERSION;
  2425.  
  2426.     /* left/right/first positions set in first call in WM_PAINT */
  2427.  
  2428.     return (f);
  2429. }
  2430.  
  2431.  
  2432. void ShowFileWindow(char *title, FILEOPTIONS *f)
  2433. {
  2434.     int RulerHeight;
  2435.     MDICREATESTRUCT mdicreate;
  2436.     RECT rect;
  2437.  
  2438.  
  2439.     /* Switch to the full menu */
  2440.  
  2441.     SwitchMenu(0);
  2442.  
  2443.     /* Create the MDI child window */
  2444.  
  2445.     GetClientRect(global.clienthwnd, &rect);
  2446.  
  2447.     mdicreate.szClass = "JWP File Parent";
  2448.     mdicreate.szTitle = title;
  2449.     mdicreate.hOwner = hInstance;
  2450.     mdicreate.x = mdicreate.y = 0;
  2451.     mdicreate.cx = rect.right;
  2452.     mdicreate.cy = rect.bottom;
  2453.     if (f->type & FN_NOSCROLLBARS) {
  2454.         mdicreate.style = WS_MAXIMIZE;
  2455.     } else {
  2456.         mdicreate.style = WS_HSCROLL | WS_VSCROLL | WS_MAXIMIZE;
  2457.     }
  2458.     mdicreate.lParam = NULL;
  2459.  
  2460.  
  2461.     /* Create the parent window */
  2462.  
  2463.     //ShowWindow(global.clienthwnd, SW_HIDE);
  2464.     //SendMessage(global.clienthwnd, WM_SETREDRAW, FALSE, 0L);
  2465.  
  2466.     curfile = f;
  2467.  
  2468.     f->hwnd = f->parent = NULL;
  2469.  
  2470.     f->parent = SendMessage (global.clienthwnd, WM_MDICREATE, 0,
  2471.                              (LONG) (LPMDICREATESTRUCT) &mdicreate);
  2472.  
  2473.     if (f->type & FN_NOSCROLLBARS) {
  2474.         SetScrollRange(f->parent, SB_VERT, 0,
  2475.                         (f->nr_lines - 1 > 0) ? f->nr_lines : 1, FALSE);
  2476.         SetScrollRange(f->parent, SB_HORZ, 0, f->linelen, FALSE);
  2477.         SetScrollPos(f->parent, SB_VERT, 0, TRUE);
  2478.         SetScrollPos(f->parent, SB_HORZ, 0, TRUE);
  2479.     }
  2480.  
  2481.     GetClientRect(f->parent, &rect);
  2482.  
  2483.  
  2484.     /* Now create the child window */
  2485.  
  2486.     if (global.showruler) {
  2487.         DisplayRuler(f, TRUE);
  2488.         RulerHeight = RULERHEIGHT;
  2489.     } else {
  2490.         RulerHeight = 0;
  2491.     }
  2492.  
  2493.     f->hwnd = CreateWindow("JWP File", NULL, WS_CHILDWINDOW | WS_VISIBLE,
  2494.                             BORDERSPACE, BORDERSPACE + RulerHeight,
  2495.                             rect.right - BORDERSPACE,
  2496.                             rect.bottom - BORDERSPACE - RulerHeight,
  2497.                             f->parent, 0, hInstance, NULL);
  2498.  
  2499.     //SendMessage(global.clienthwnd, WM_SETREDRAW, TRUE, 0L);
  2500.     //ShowWindow(global.clienthwnd, SW_SHOW);
  2501.  
  2502.     ShowWindow(f->parent, SW_SHOW);
  2503.     ShowWindow(f->hwnd, SW_SHOW);
  2504.  
  2505.     FillCPos(f, CURPARA(f), 0, -1);
  2506.  
  2507.     SetFocus(f->hwnd);
  2508. }
  2509.